Creating a script to reconcile identifiers by Object Number (number(obj))

I have a list of Objects IDs dump into a file. They are out of order and i need to create a report to display the the content of those ids. I created a function to display the information that;s all good. The bad thing is that i can not get them SORT by Object Number properly.
For example I'm getting this:

12.1 Heading 12.1
12.1.0-1 Text of Heading 12.1
2 Heading 2
2.0-1 Text of Heading 2
2.0-10 Text of Heading 2
2.0-11 Text of Heading 2
2.0-2 Text of Heading 2

That happens when I use the Skip List.

How can i possible read from that file and compare the object number and sort it in a spreadsheet.

All i need is a function to sort by Object Number. Any help will be appreaciated. Thanks.
SystemAdmin - Wed Oct 27 17:28:40 EDT 2010

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
rmoskwa - Thu Oct 28 11:51:55 EDT 2010

I assume that you want to sort using Excel.

You can Google Excel sort decimal, and get lots of advice on how to sort this type of data.

I also found an interesting addin at
http://www.contextures.com/excel-sort-addin.html

I haven't used it.
A free eval copy is available.
It is not very expensive either.

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
SystemAdmin - Fri Oct 29 07:12:37 EDT 2010

Sorting based on Object Numbers, look at http://www.smartdxl.com/content/?page_id=149

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
Mathias Mamsch - Tue Jan 25 10:17:31 EST 2011

SystemAdmin - Fri Oct 29 07:12:37 EDT 2010
Sorting based on Object Numbers, look at http://www.smartdxl.com/content/?page_id=149

I am getting crazy with those "Object Number" sorting. Can anyone please confirm, that the "lexnum" stuff and other simple padding algorithms of object number do NOT work as expected on this kind of Module Structure:
 

Object Level   Object Number   Heading / Text 
     1               1            Heading
     2               1.1          Heading
     1 <- no typo!   1-1          Text

 


Since "-" is lexically smaller than "." even padding to "00001", "00001.00001", "00001-00001" will not work. The lexnum code on smartdxl makes two times "00001.00001" from that which is even worse.

Is replacing "-" by something else sufficient to solve that issue? Am I missing something obvious? I know this has been discussed several times but the keywords 'sort number' did not bring me to the right post, so can someone hint to a working 'lexnum' function here in the forum? :-)

Regards, Mathias

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
llandale - Tue Jan 25 12:58:03 EST 2011

Mathias Mamsch - Tue Jan 25 10:17:31 EST 2011

I am getting crazy with those "Object Number" sorting. Can anyone please confirm, that the "lexnum" stuff and other simple padding algorithms of object number do NOT work as expected on this kind of Module Structure:
 

Object Level   Object Number   Heading / Text 
     1               1            Heading
     2               1.1          Heading
     1 <- no typo!   1-1          Text

 


Since "-" is lexically smaller than "." even padding to "00001", "00001.00001", "00001-00001" will not work. The lexnum code on smartdxl makes two times "00001.00001" from that which is even worse.

Is replacing "-" by something else sufficient to solve that issue? Am I missing something obvious? I know this has been discussed several times but the keywords 'sort number' did not bring me to the right post, so can someone hint to a working 'lexnum' function here in the forum? :-)

Regards, Mathias

 

 

 


Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS

 

 

I'm not seeing the problem. ... snip ... investigate ... OK, now I indeed see the problem; it occurs when a text object is placed after a sibling Heading object. So I fixed my functions, which I now defy anybody to show a situation where the displayed objects are not in fact in the same order as shown in the Standard View.

//**************
bool    not(bool InBool)
{     // Invert the input boolean.
        // This allows other scripts to write things like:
        //   if (not CheckResults), rather than
        //   if (! CheckResults)
        // When combined with "or" and "and", it makes Boolean expressions easier to read.
        return(!InBool)
}     // end not()
 
 
const string    cl_fPadParaZeros = "0000000000"
Buffer  gl_bufPadOut    = create()      // Internal buffer for the following fPadPara and fPadID
//******************
string  fPadPara(string ParaNum, int NumDigits)
{     // Pad each numeric field of the Para Number with leading Zeros.
        // i.e. if "NumDigits" is 3 then convert
        //   "3.2.3-0.29.4444" to "003,002,003-000,029,4444"
        // This is useful before sorting paragraph numbers alpha-numerically
        // See sister function "fUnPadPara()"
        // NumDigits must be <= 10 (defined length of cl_fPadParaZeros)
        // Note that legal paragraph numbers have delimiters "." and "-".
        // Since the dash '-' sorts before a period '.', sorting fails when
        //      a text object follows a sibling Heading object.
        // Thus the period is replaced with a comma ',' to support sorting,
        //      and comma's are replaced back to periods in sibling fUnPadPara() below.
 
 
        int     Start, End      // Bounds of each number field; either pointing
                                //   to the Delimiters or the beginning or end of
                                //   ParaNum
        int     LenPara = length(ParaNum)
        string  SubStr  // Part between Delimiters (a number field)
        int     LenSub  // length of SubString
        char    Delim           // Actual Delimiter.
 
        if (LenPara <= 0) return("")
        gl_bufPadOut = ""
        Start   = -1
        while (Start < LenPara)
        {  Delim = null
                // Find the next SubString, which is between'
                //   the legal Paragraph Delimiters "." and "-".
           for (End = Start+1; End < LenPara; End++)
           {  if (ParaNum[End] == '.'         or
                  ParaNum[End] == ','   or
                  ParaNum[End] == '-')
              {  Delim = ParaNum[End]
                 break
              }
           }
           if (Delim == '.') then Delim = ','
                // End now points to the next Delimiter or is
                //   beyond the end of ParaNum
           SubStr        = ParaNum[Start+1:End-1]
           LenSub        = length(SubStr)
           if (NumDigits-LenSub-1 >=0)
              gl_bufPadOut      += cl_fPadParaZeros[0:NumDigits-LenSub-1]       // Pad with Zeros
           gl_bufPadOut         += SubStr
           if (not null Delim) gl_bufPadOut += Delim
//           print Start "\t" End "\t'" SubStr "'\n"
           Start         = End  // Reposition for next pass
        }     // end while more ParaNum to parse.
 
        return(stringOf(gl_bufPadOut))
}    // end fPadPara()  
 
 
//************************
string  fUnPadPara(string ParaNum)
{    // Strip the padding inserted by sibling function "fPadPara()".
        // I.E. convert "003,002,003-000.029.4444" to "3.2.3-0.29.4444"
        // Note that at least one digit will remain (the zero in '0.29')
 
        int     Start, End      // Positions of . or - in ParaNum.
        int     LenPara = length(ParaNum)
        char    Delim
        bool    UnPad
 
        gl_bufPadOut    = ""
        Start   = -1
        while (Start < LenPara)
        {  Delim     = null
           UnPad        = true
           for (End = Start+1; End < LenPara; End++)
           {                 // Strip all leading Zeros; which means stop UnPadding
                        //   when  the first non-Zero character is encountered.
              if (UnPad and ParaNum[End] == '0')
                 Start = End
              else {UnPad = false}
              if (ParaNum[End] == '.'   or
                  ParaNum[End] == ','   or
                  ParaNum[End] == '-')
              {  Delim = ParaNum[End]
                 break
              }
           } // End found Delim or end of ParaNum
           if (Delim == ',') then Delim = '.'
//       print Start "\t" End "\t" "\n"
           if (Start+1 > End-1)
               Start--  // Allow last Zero
           gl_bufPadOut += ParaNum[Start+1:End-1]
           if (not null Delim) gl_bufPadOut += Delim
           Start         = End
        }    // end while more ParaNum to Parse
        return(stringOf(gl_bufPadOut))
}    // end fUnPadPara()
 
 
// ********** BEGIN MAIN Testing *****************
 
Skip    skp = createString() // KEY 'string' ID; DATA 'string' Padded para num
string  ParaYesPadded, ParaNotPadded, ID
Object  obj
 
for obj in (current Module) do
{  ParaNotPadded = number(obj)
   ParaYesPadded = fPadPara(ParaNotPadded, 3)
   put(skp, ParaYesPadded, identifier(obj))
}
 
for ID in skp do
{  ParaYesPadded = (string key skp)
   ParaNotPadded = fUnPadPara(ParaYesPadded)
   print ID " \t" ParaNotPadded "\t\t[" ParaYesPadded "]\n"
}
delete(skp)


These are very old functions and if you want to tweak them, especially the comments, go ahead.

 

 

  • Louie


You know, "defy" means "please test it for me"!

 

 

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
Mathias Mamsch - Wed Jan 26 13:02:36 EST 2011

llandale - Tue Jan 25 12:58:03 EST 2011

I'm not seeing the problem. ... snip ... investigate ... OK, now I indeed see the problem; it occurs when a text object is placed after a sibling Heading object. So I fixed my functions, which I now defy anybody to show a situation where the displayed objects are not in fact in the same order as shown in the Standard View.

//**************
bool    not(bool InBool)
{     // Invert the input boolean.
        // This allows other scripts to write things like:
        //   if (not CheckResults), rather than
        //   if (! CheckResults)
        // When combined with "or" and "and", it makes Boolean expressions easier to read.
        return(!InBool)
}     // end not()
 
 
const string    cl_fPadParaZeros = "0000000000"
Buffer  gl_bufPadOut    = create()      // Internal buffer for the following fPadPara and fPadID
//******************
string  fPadPara(string ParaNum, int NumDigits)
{     // Pad each numeric field of the Para Number with leading Zeros.
        // i.e. if "NumDigits" is 3 then convert
        //   "3.2.3-0.29.4444" to "003,002,003-000,029,4444"
        // This is useful before sorting paragraph numbers alpha-numerically
        // See sister function "fUnPadPara()"
        // NumDigits must be <= 10 (defined length of cl_fPadParaZeros)
        // Note that legal paragraph numbers have delimiters "." and "-".
        // Since the dash '-' sorts before a period '.', sorting fails when
        //      a text object follows a sibling Heading object.
        // Thus the period is replaced with a comma ',' to support sorting,
        //      and comma's are replaced back to periods in sibling fUnPadPara() below.
 
 
        int     Start, End      // Bounds of each number field; either pointing
                                //   to the Delimiters or the beginning or end of
                                //   ParaNum
        int     LenPara = length(ParaNum)
        string  SubStr  // Part between Delimiters (a number field)
        int     LenSub  // length of SubString
        char    Delim           // Actual Delimiter.
 
        if (LenPara <= 0) return("")
        gl_bufPadOut = ""
        Start   = -1
        while (Start < LenPara)
        {  Delim = null
                // Find the next SubString, which is between'
                //   the legal Paragraph Delimiters "." and "-".
           for (End = Start+1; End < LenPara; End++)
           {  if (ParaNum[End] == '.'         or
                  ParaNum[End] == ','   or
                  ParaNum[End] == '-')
              {  Delim = ParaNum[End]
                 break
              }
           }
           if (Delim == '.') then Delim = ','
                // End now points to the next Delimiter or is
                //   beyond the end of ParaNum
           SubStr        = ParaNum[Start+1:End-1]
           LenSub        = length(SubStr)
           if (NumDigits-LenSub-1 >=0)
              gl_bufPadOut      += cl_fPadParaZeros[0:NumDigits-LenSub-1]       // Pad with Zeros
           gl_bufPadOut         += SubStr
           if (not null Delim) gl_bufPadOut += Delim
//           print Start "\t" End "\t'" SubStr "'\n"
           Start         = End  // Reposition for next pass
        }     // end while more ParaNum to parse.
 
        return(stringOf(gl_bufPadOut))
}    // end fPadPara()  
 
 
//************************
string  fUnPadPara(string ParaNum)
{    // Strip the padding inserted by sibling function "fPadPara()".
        // I.E. convert "003,002,003-000.029.4444" to "3.2.3-0.29.4444"
        // Note that at least one digit will remain (the zero in '0.29')
 
        int     Start, End      // Positions of . or - in ParaNum.
        int     LenPara = length(ParaNum)
        char    Delim
        bool    UnPad
 
        gl_bufPadOut    = ""
        Start   = -1
        while (Start < LenPara)
        {  Delim     = null
           UnPad        = true
           for (End = Start+1; End < LenPara; End++)
           {                 // Strip all leading Zeros; which means stop UnPadding
                        //   when  the first non-Zero character is encountered.
              if (UnPad and ParaNum[End] == '0')
                 Start = End
              else {UnPad = false}
              if (ParaNum[End] == '.'   or
                  ParaNum[End] == ','   or
                  ParaNum[End] == '-')
              {  Delim = ParaNum[End]
                 break
              }
           } // End found Delim or end of ParaNum
           if (Delim == ',') then Delim = '.'
//       print Start "\t" End "\t" "\n"
           if (Start+1 > End-1)
               Start--  // Allow last Zero
           gl_bufPadOut += ParaNum[Start+1:End-1]
           if (not null Delim) gl_bufPadOut += Delim
           Start         = End
        }    // end while more ParaNum to Parse
        return(stringOf(gl_bufPadOut))
}    // end fUnPadPara()
 
 
// ********** BEGIN MAIN Testing *****************
 
Skip    skp = createString() // KEY 'string' ID; DATA 'string' Padded para num
string  ParaYesPadded, ParaNotPadded, ID
Object  obj
 
for obj in (current Module) do
{  ParaNotPadded = number(obj)
   ParaYesPadded = fPadPara(ParaNotPadded, 3)
   put(skp, ParaYesPadded, identifier(obj))
}
 
for ID in skp do
{  ParaYesPadded = (string key skp)
   ParaNotPadded = fUnPadPara(ParaYesPadded)
   print ID " \t" ParaNotPadded "\t\t[" ParaYesPadded "]\n"
}
delete(skp)


These are very old functions and if you want to tweak them, especially the comments, go ahead.

 

 

  • Louie


You know, "defy" means "please test it for me"!

 

 

Thanks Louie, that seems to work fine :-) Regards, Mathias

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
SystemAdmin - Fri Feb 11 08:11:39 EST 2011

Mathias Mamsch - Wed Jan 26 13:02:36 EST 2011
Thanks Louie, that seems to work fine :-) Regards, Mathias

This is a great code, now i need to sort all in a ListView Column.
Can anyone try this code and provide a possible solution so that we can sort by column everything at once.

DB win
DBE lv
Skip sortSkip = createString
string arr[6] = {"3.1-2","1.3","3.1-1","1.2.3","1.10","2.3.4.5"}
 
string getNextEnumeratedValue(string &sEnumerated, Regexp reg) {
      string result
      if (!reg sEnumerated) {
            sEnumerated = ""
            return ""
      }
      result = sEnumerated[0: (start 0)-1]
      sEnumerated = sEnumerated[end 0 +1:]
      return result
} // end getNextEnumeratedValue
 
int sReqLoop(string a, string b){
      return 0
}
 
int sReqWoot(string a, string b){
      Regexp reg = regexp "(\\.|-)"
      string atemp = a
      string btemp = b
      string ap, bp
      int iap, ibp
 
      while(atemp != ""){
            if(isValidInt(atemp)){
                  iap = intOf atemp
                  ap = atemp
                  atemp = null
                  }
            else{
                  ap = getNextEnumeratedValue(atemp, reg)
                  iap = intOf ap
            }
            if(isValidInt(btemp)){
                  ibp = intOf btemp
                  bp = btemp
                  btemp = null
                  }
            else{
                  bp = getNextEnumeratedValue(btemp, reg)
                  ibp = intOf bp
            }
            if(iap > ibp)
                  return 1
            else if(ibp > iap)
                  return -1
      }
      return 0
}
 
win = centered("Testing Sorting")
lv = listView(win,listViewOptionSortText,200, 10, arr)
realize(win)
insertColumn(lv,0,"Lista", 85, iconNone)
set(lv, 0, sReqWoot)
show(win)

Re: Creating a script to reconcile identifiers by Object Number (number(obj))
RianWouters - Wed Sep 14 10:21:13 EDT 2011

llandale - Tue Jan 25 12:58:03 EST 2011

I'm not seeing the problem. ... snip ... investigate ... OK, now I indeed see the problem; it occurs when a text object is placed after a sibling Heading object. So I fixed my functions, which I now defy anybody to show a situation where the displayed objects are not in fact in the same order as shown in the Standard View.

//**************
bool    not(bool InBool)
{     // Invert the input boolean.
        // This allows other scripts to write things like:
        //   if (not CheckResults), rather than
        //   if (! CheckResults)
        // When combined with "or" and "and", it makes Boolean expressions easier to read.
        return(!InBool)
}     // end not()
 
 
const string    cl_fPadParaZeros = "0000000000"
Buffer  gl_bufPadOut    = create()      // Internal buffer for the following fPadPara and fPadID
//******************
string  fPadPara(string ParaNum, int NumDigits)
{     // Pad each numeric field of the Para Number with leading Zeros.
        // i.e. if "NumDigits" is 3 then convert
        //   "3.2.3-0.29.4444" to "003,002,003-000,029,4444"
        // This is useful before sorting paragraph numbers alpha-numerically
        // See sister function "fUnPadPara()"
        // NumDigits must be <= 10 (defined length of cl_fPadParaZeros)
        // Note that legal paragraph numbers have delimiters "." and "-".
        // Since the dash '-' sorts before a period '.', sorting fails when
        //      a text object follows a sibling Heading object.
        // Thus the period is replaced with a comma ',' to support sorting,
        //      and comma's are replaced back to periods in sibling fUnPadPara() below.
 
 
        int     Start, End      // Bounds of each number field; either pointing
                                //   to the Delimiters or the beginning or end of
                                //   ParaNum
        int     LenPara = length(ParaNum)
        string  SubStr  // Part between Delimiters (a number field)
        int     LenSub  // length of SubString
        char    Delim           // Actual Delimiter.
 
        if (LenPara <= 0) return("")
        gl_bufPadOut = ""
        Start   = -1
        while (Start < LenPara)
        {  Delim = null
                // Find the next SubString, which is between'
                //   the legal Paragraph Delimiters "." and "-".
           for (End = Start+1; End < LenPara; End++)
           {  if (ParaNum[End] == '.'         or
                  ParaNum[End] == ','   or
                  ParaNum[End] == '-')
              {  Delim = ParaNum[End]
                 break
              }
           }
           if (Delim == '.') then Delim = ','
                // End now points to the next Delimiter or is
                //   beyond the end of ParaNum
           SubStr        = ParaNum[Start+1:End-1]
           LenSub        = length(SubStr)
           if (NumDigits-LenSub-1 >=0)
              gl_bufPadOut      += cl_fPadParaZeros[0:NumDigits-LenSub-1]       // Pad with Zeros
           gl_bufPadOut         += SubStr
           if (not null Delim) gl_bufPadOut += Delim
//           print Start "\t" End "\t'" SubStr "'\n"
           Start         = End  // Reposition for next pass
        }     // end while more ParaNum to parse.
 
        return(stringOf(gl_bufPadOut))
}    // end fPadPara()  
 
 
//************************
string  fUnPadPara(string ParaNum)
{    // Strip the padding inserted by sibling function "fPadPara()".
        // I.E. convert "003,002,003-000.029.4444" to "3.2.3-0.29.4444"
        // Note that at least one digit will remain (the zero in '0.29')
 
        int     Start, End      // Positions of . or - in ParaNum.
        int     LenPara = length(ParaNum)
        char    Delim
        bool    UnPad
 
        gl_bufPadOut    = ""
        Start   = -1
        while (Start < LenPara)
        {  Delim     = null
           UnPad        = true
           for (End = Start+1; End < LenPara; End++)
           {                 // Strip all leading Zeros; which means stop UnPadding
                        //   when  the first non-Zero character is encountered.
              if (UnPad and ParaNum[End] == '0')
                 Start = End
              else {UnPad = false}
              if (ParaNum[End] == '.'   or
                  ParaNum[End] == ','   or
                  ParaNum[End] == '-')
              {  Delim = ParaNum[End]
                 break
              }
           } // End found Delim or end of ParaNum
           if (Delim == ',') then Delim = '.'
//       print Start "\t" End "\t" "\n"
           if (Start+1 > End-1)
               Start--  // Allow last Zero
           gl_bufPadOut += ParaNum[Start+1:End-1]
           if (not null Delim) gl_bufPadOut += Delim
           Start         = End
        }    // end while more ParaNum to Parse
        return(stringOf(gl_bufPadOut))
}    // end fUnPadPara()
 
 
// ********** BEGIN MAIN Testing *****************
 
Skip    skp = createString() // KEY 'string' ID; DATA 'string' Padded para num
string  ParaYesPadded, ParaNotPadded, ID
Object  obj
 
for obj in (current Module) do
{  ParaNotPadded = number(obj)
   ParaYesPadded = fPadPara(ParaNotPadded, 3)
   put(skp, ParaYesPadded, identifier(obj))
}
 
for ID in skp do
{  ParaYesPadded = (string key skp)
   ParaNotPadded = fUnPadPara(ParaYesPadded)
   print ID " \t" ParaNotPadded "\t\t[" ParaYesPadded "]\n"
}
delete(skp)


These are very old functions and if you want to tweak them, especially the comments, go ahead.

 

 

  • Louie


You know, "defy" means "please test it for me"!

 

 

Unfortunately DOORS 9.3 does not sort as you would expect: for example, '-' comes before ','.
But also "a" "b" "A" "B" sorts as "a" "A" "b" "B"...
Why?????

I fixed the duplicate script with the following padding script, which is basically functionally equivalent to the one from Louie above, but shorter.

Only changes it that it uses "_" iso "," because that is sorted before "-"

string pad(string num, int digits)
{
int start = 0, end = 0
num = num "."
char d
string r = ""
int lnum = length(num)
while (end < lnum) {
d = numend
if (d == '.' || d == ',' || d == '-') {
if (d == '.') d = '_'
r = r ZEROS0:digits-end+start-1 numstart:end-1 d ""
start = end + 1
n = 0
}
end++
}
return r0:length(r)-2
} // end pad()